/*
 * @(#)XfsimProcess.java        2003/01/01
 *
 * This file is part of Xfuzzy 3.0, a design environment for fuzzy logic
 * based systems.
 *
 * (c) 2000 IMSE-CNM. The authors may be contacted by the email address:
 *                    xfuzzy-team@imse.cnm.es
 *
 * Xfuzzy is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation.
 *
 * Xfuzzy is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 */

package xfuzzy.xfsim.model;

import xfuzzy.PlantModel;
import xfuzzy.lang.*;
import xfuzzy.util.*;
import javax.swing.JFrame;

/**
 * Hilo del proceso de simulaci�n
 * 
 * @author Francisco Jos� Moreno Velo
 *
 */
public class XfsimThread implements Runnable {
	
	//----------------------------------------------------------------------------//
	//                            MIEMBROS PRIVADOS                               //
	//----------------------------------------------------------------------------//

	/**
	 * Configuraci�n del proceso
	 */
	private XfsimConfig config;
	
	/**
	 * Estado del proceso
	 */
	private XfsimStatus status;
	
	/**
	 * Tuber�a de comunicaci�n con la ventana gr�fica
	 */
	private XfsimPipe pipe;
	
	/**
	 * Sistema difuso sobre el que se aplica el proceso
	 */
	private Specification spec;
	
	/**
	 * Ficheros de log del proceso de simulaci�n
	 */
	private XfsimLog[] log;
	
	/**
	 * Ventanas de representaci�n gr�fica del proceso de simulaci�n
	 */
	private XfsimPlotFrame[] plot;
	
	/**
	 * Ventana de la que van a depender las representaciones gr�ficas
	 */
	private JFrame frame;
	
	/**
	 * M�dulo principal del sistema difuso
	 */
	private SystemModule system;
	
	/**
	 * Planta sobre la que actua el sistema difuso
	 */
	private PlantModel plant;
	
	/**
	 * Instante de comienzo de la simulaci�n
	 */
	private long begin;
	
	/**
	 * Iteraci�n actual
	 */
	private int iteration;
	
	/**
	 * Valor actual de las salidas del sistema difuso
	 */
	private double[] fuzzystate;
	
	/**
	 * Valor actual de las salidas de la planta
	 */
	private double[] plantstate;

	//----------------------------------------------------------------------------//
	//                                CONSTRUCTOR                                 //
	//----------------------------------------------------------------------------//

	/**
	 * Constructor
	 */
	public XfsimThread(Specification spec, XfsimConfig config, JFrame frame, XfsimPipe pipe) {
		this.spec = spec;
		this.config = config;
		this.pipe = pipe;
		this.frame = frame;
		buildOutputs();
	}
	
	/**
	 * Constructor
	 */
	public XfsimThread(Specification spec, XfsimConfig config) {
		this.spec = spec;
		this.config = config;
		this.pipe = null;
		this.frame = null;
		buildOutputs();
	}
	
	//----------------------------------------------------------------------------//
	//                             M�TODOS P�BLICOS                               //
	//----------------------------------------------------------------------------//

	/**
	 * Ejecuci�n del hilo
	 */
	public void run() {
		if(!config.isConfigured()) return;
		
		this.system = spec.getSystemModule();
		this.plant = config.getPlantModel();
		XfsimLimit limit = config.getLimit();
		double[] init = config.getPlantInit();
		this.begin = System.currentTimeMillis();
		open();
		
		try { 
			if(init == null) plant.init();
			else plant.init(init);
		} catch(Exception ex) {
			if(frame != null) XDialog.showMessage(frame,ex.toString());
			else System.out.println(ex.toString());
			return;
		}
		
		this.iteration = 0;
		this.plantstate = plant.state();
		
		iteration();
		communication();		
		while(limit.test(status)) {
			iteration();
			communication();
		}
		
		if(pipe == null) {
			close();
		} else {
			end();		
			while(this.status.getStatus() != XfsimStatus.FINISHED) {
				communication();
				try { Thread.sleep(100); } catch(Exception ex) {}
			}
		}
	}

	//----------------------------------------------------------------------------//
	//                             M�TODOS PRIVADOS                               //
	//----------------------------------------------------------------------------//

	/**
	 * Comunicaci�n del estado del sistema
	 */
	private void communication() {
		if(this.pipe == null) return;
		this.pipe.put(this.status.duplicate());
		int msg=this.pipe.getCommand();
		if(msg == XfsimPipe.NOMSG) return;
		if(msg == XfsimPipe.STOP) {
			int laststat = this.status.getStatus();
			this.status.setStatus(XfsimStatus.STOPPED);
			this.pipe.put( this.status.duplicate());
			while(msg != XfsimPipe.CONTINUE && msg != XfsimPipe.FINISH) {
				try{ Thread.sleep(100); } catch(InterruptedException e) {}
				msg=this.pipe.getCommand();
			}
			if(msg == XfsimPipe.FINISH) {
				this.status.setStatus(XfsimStatus.FINISHED);
				this.plant.close();
			}
			if(msg == XfsimPipe.CONTINUE) {
				this.status.setStatus(laststat);
			}
			this.pipe.put(this.status.duplicate());
		}
	}
	
	/**
	 * Abre los elementos de salida del proceso de simulaci�n
	 */
	private void open() {
		for(int i=0; i<log.length; i++) log[i].open();
		for(int i=0; i<plot.length; i++) plot[i].open();
	}
	
	/**
	 * Cierra los ficheros de log al finalizar la simulaci�n
	 */
	private void end() {
		for(int i=0; i<log.length; i++) log[i].close();
	}	
	
	/**
	 * Cierra los ficheros de log y las representaciones al finalizar la simulaci�n
	 */
	private void close() {
		plant.close();
		for(int i=0; i<log.length; i++) log[i].close();
		for(int i=0; i<plot.length; i++) plot[i].close();
	}	
	
	/**
	 * Vuelca los resultados de una iteraci�n en las salidas
	 */
	private void iteration() {
		
		fuzzystate = system.crispInference(plantstate);
		plantstate = plant.compute(fuzzystate);
		double time = System.currentTimeMillis();
		iteration++;
		status = new XfsimStatus(XfsimStatus.RUNNING,iteration,time-begin,fuzzystate,plantstate);
		
		for(int i=0; i<log.length; i++) log[i].iter(status);
		for(int i=0; i<plot.length; i++) plot[i].iter(status);
		
		
	}
	
	/**
	 * Contruye el las listas log y plot a partir de los datos de config
	 */
	private void buildOutputs() {
		XfsimOutput[] output = config.getOutputs();
		int lcount = 0;
		int pcount = 0;
		for(int i=0; i<output.length; i++) {
			if(output[i] instanceof XfsimLog) lcount++;
			if(output[i] instanceof XfsimPlot) pcount++;
		}
		
		this.log = new XfsimLog[lcount];
		this.plot = new XfsimPlotFrame[pcount];
		for(int i=0,l=0,p=0; i<output.length; i++) {
			if(output[i] instanceof XfsimLog) { log[l] = (XfsimLog) output[i]; l++; }
			if(output[i] instanceof XfsimPlot) { plot[p] = new XfsimPlotFrame(frame,(XfsimPlot) output[i],spec); p++; }
		}	
	}
}
